package com.pbd.client.utils;
import java.util.Date;


/**
 * This is a simple regular expression based parser for date notations.
 * While our aim is to fully support in the future the JDK date parser, currently
 * only numeric notations and literals are supported such as <code>dd/MM/yyyy HH:mm:ss.SSSS</code>.
 * Each entity is parsed with the same number of digits, i.e. for <code>dd</code> two digits will be
 * parsed while for <code>d</code> only one will be parsed.
 * @author cogent
 *
 */

public class SimpleDateParser {


  private final static String DAY_IN_MONTH = "d";

  private final static String MONTH = "M";

  private final static String YEAR = "y";

  private final static String LITERAL = "\\";

  private final static int DATE_PATTERN = 0;

  private final static int REGEX_PATTERN = 1;

  private final static int COMPONENT = 2;

  private final static int REGEX = 0;

  private final static int INSTRUCTION = 1;

  private final static String[] TOKENS[] = {
  { "SSSS", "(\\d\\d\\d\\d)",DateLocale.TOKEN_MILLISECOND }, 
  { "SSS", "(\\d\\d\\d)", DateLocale.TOKEN_MILLISECOND },
  { "SS", "(\\d\\d)", DateLocale.TOKEN_MILLISECOND }, 
  { "S", "(\\d)", DateLocale.TOKEN_MILLISECOND },
  { "ss", "(\\d\\d)", DateLocale.TOKEN_SECOND }, 
  { "s", "(\\d)", DateLocale.TOKEN_SECOND },
  { "mm", "(\\d\\d)", DateLocale.TOKEN_MINUTE }, 
  { "m", "(\\d)", DateLocale.TOKEN_MINUTE},
  { "HH", "(\\d\\d)", DateLocale.TOKEN_HOUR_24},
  { "H", "(\\d)", DateLocale.TOKEN_HOUR_24 },
  { "dd", "(\\d\\d)", DateLocale.TOKEN_DAY_OF_MONTH }, 
  { "d", "(\\d)", DateLocale.TOKEN_DAY_OF_MONTH },
  { "MM", "(\\d\\d)", DateLocale.TOKEN_MONTH }, 
  { "M", "(\\d)", DateLocale.TOKEN_MONTH },
  { "yyyy", "(\\d\\d\\d\\d)", DateLocale.TOKEN_YEAR }, 
  { "yyy", "(\\d\\d\\d)", DateLocale.TOKEN_YEAR },
  { "yy", "(\\d\\d)", DateLocale.TOKEN_YEAR }, 
  { "y", "(\\d)", DateLocale.TOKEN_YEAR }
  };

  private Pattern regularExpression;;

  private String instructions = "";

  private static void _parse(String format, String[] args) {
    if (format.length() == 0)
      return;
    if (format.startsWith("'")){
      format = format.substring(1);
      int end = format.indexOf("'");
      if (end == -1)
        throw new IllegalArgumentException("Unmatched single quotes.");
      args[REGEX]+=Pattern.quote(format.substring(0,end));
      format = format.substring(end+1);
    }
    for (int i = 0; i < TOKENS.length; i++) {
      String[] row = TOKENS[i];
      String datePattern = row[DATE_PATTERN];
      if (!format.startsWith(datePattern))
        continue;
      format = format.substring(datePattern.length());
      args[REGEX] += row[REGEX_PATTERN];
      args[INSTRUCTION] += row[COMPONENT];
      _parse(format, args);
      return;
    }
    args[REGEX] += Pattern.quote(""+format.charAt(0));
    format = format.substring(1);
    _parse(format, args);
  }

  private static void load(Date date, String text, String component) {
    if (component.equals(DateLocale.TOKEN_MILLISECOND)) {
      //TODO: implement
    }

    if (component.equals(DateLocale.TOKEN_SECOND)) {
      date.setSeconds(Integer.parseInt(text));
    }

    if (component.equals(DateLocale.TOKEN_MINUTE)) {
      date.setMinutes(Integer.parseInt(text));
    }

    if (component.equals(DateLocale.TOKEN_HOUR_24)) {
      date.setHours(Integer.parseInt(text));
    }

    if (component.equals(DateLocale.TOKEN_DAY_OF_MONTH)) {
      date.setDate(Integer.parseInt(text));
    }
    if (component.equals(DateLocale.TOKEN_MONTH)) {
      date.setMonth(Integer.parseInt(text)-1);
    }
    if (component.equals(DateLocale.TOKEN_YEAR)) {
      //TODO: fix for short patterns
      date.setYear(Integer.parseInt(text)-1900);
    }

  }

  public SimpleDateParser(String format) {
    String[] args = new String[] { "", "" };
    _parse(format, args);
    regularExpression = new Pattern(args[REGEX]);
    instructions = args[INSTRUCTION];
  }

  public Date parse(String input) {
    Date date = new Date(0, 0, 0, 0, 0, 0);
    String matches[] = regularExpression.match(input);
    if (matches == null)
      throw new IllegalArgumentException(input+" does not match "+regularExpression.pattern());
    if (matches.length-1!=instructions.length())
      throw new IllegalArgumentException("Different group count - "+input+" does not match "+regularExpression.pattern());
    for (int group = 0; group < instructions.length(); group++) {
      String match = matches[group + 1];
      load(date, match, ""+instructions.charAt(group));
    }
    return date;
  }
  
  public static Date parse(String input, String pattern){
    return new SimpleDateParser(pattern).parse(input);
  }
}


